using IQIGame.Onigao.Game;
using System;

namespace IQIGame.Onigao.Logic
{
    public struct FixedOBBRect
    {
        public Vector3Logic center { private set; get; }
        public float rotationRad { private set; get; }
        public Vector2Logic halfSize { private set; get; }
        public Vector2Logic axissX { private set; get; }
        public Vector2Logic axissZ { private set; get; }

        public FixedOBBRect(Vector3Logic center, Vector3Logic size, float yRotation)
        {
            this.center = center;
            this.halfSize = new Vector2Logic(size.x / 2, size.z / 2);
            this.rotationRad = yRotation * MathLogic.Deg2Rad;
            axissX = new Vector2Logic((float)Math.Cos(rotationRad), -(float)Math.Sin(rotationRad));
            axissZ = new Vector2Logic(-axissX.y, axissX.x);
        }

        public float Dot(Vector2Logic a, Vector2Logic b)
        {
            return Math.Abs(a.x * b.x + a.y * b.y);
        }

        public float GetProjectionRadius(Vector2Logic axis)
        {
            return (halfSize.x * Dot(axissX, axis) + halfSize.y * Dot(axissZ, axis));
        }

        private bool CheckProjection(ref FixedOBBRect other, ref Vector2Logic curVector2, ref Vector2Logic distanceVector)
        {
            if ((GetProjectionRadius(curVector2) + other.GetProjectionRadius(curVector2)) <= Dot(distanceVector, curVector2))
            {
                return true;
            }
            return false;
        }

        public bool IsIntersecting(FixedOBBRect other)
        {
            Vector2Logic distanceVector = new Vector2Logic(center.x - other.center.x, center.z - other.center.z);

            var axiss = axissX;
            if (CheckProjection(ref other, ref axiss, ref distanceVector))
            {
                return false;
            }
            axiss = axissZ;
            if (CheckProjection(ref other, ref axiss, ref distanceVector))
            {
                return false;
            }

            axiss = other.axissX;
            if (CheckProjection(ref other, ref axiss, ref distanceVector))
            {
                return false;
            }

            axiss = other.axissZ;
            if (CheckProjection(ref other, ref axiss, ref distanceVector))
            {
                return false;
            }

            return true;
        }

        public bool Contains(Vector2Logic point)
        {
            // 将点的坐标转换到矩形的本地坐标系（相对于center，该值的参考坐标系旋转值和世界坐标系一致）
            Vector2Logic localPoint = point - new Vector2Logic(center.x, center.z);

            // 将点的坐标旋转到矩形的方向（计算该坐标在OBBRectx轴和z轴上的投影，获取旋转角度一致的情况下，point在OBBRect内部的real localPosition）
            float rotatedX = localPoint.x * axissX.x + localPoint.y * axissX.y;
            float rotatedY = localPoint.x * axissZ.x + localPoint.y * axissZ.y;

            // 检查旋转后的点是否在矩形的范围内
            return Math.Abs(rotatedX) <= halfSize.x && Math.Abs(rotatedY) <= halfSize.y;
        }
    }
}
